package command

import (
	"io"
	"net/http"
	"runtime"

	library "../library"
	HTTP "../library/http"
	protocol "../library/httplib/protocol"
	key "../library/key"
	"golang.org/x/net/websocket"
)

// HTTPCommand http终端接口
//  路由接口
// 	   Path			定义路由前戳
//     Path/Run     	执行一个终端
//     Path/Exec    	执行终端命令
//     Path/Exit   		关闭指定终端
//     Path/HeartBeat   心跳包
type HTTPCommand struct {
	// 路由设置
	Path        string     // 路由前戳
	Handle      *HTTP.HTTP // 目标路由
	CrossDomain bool       // 跨域设置
	// 认证设置
	Key             *key.Key        // Key认证
	UsingKey        bool            // 启用Key认证
	VisitLimit      HTTP.VisitLimit // 访问认证
	UsingVisitLimit bool            // 启用访问认证
	// 终端管理
	timeID        int64               // 计时器 ID
	management    map[string]*Command // 终端队列
	ManagementKey *key.Key            // 终端Key认证
}

// NewCommand 创建终端
func (H *HTTPCommand) NewCommand() {
	H.management = make(map[string]*Command)
	// 超时处理 生命周期 5分钟
	H.timeID = library.Cycle.ADD(300000, func() {
		for key, cmd := range H.management {
			// 判断是否已经释放
			// 	ManagementKey key不存在则是孤立的终端可以进行销毁
			if _, ok := H.ManagementKey.UserList[key]; !ok {
				// 销毁
				cmd.Exit()
				delete(H.management, key)
			}
		}
	})
	// ---------------------Run 运行终端---------------------
	Run := &protocol.Protocol{
		Path:   H.Path + `/Run`,
		RegExp: false,
		// Key设置
		Key:              H.Key,
		UsingKey:         H.UsingKey,
		UsingToPrivilege: true, // 使用权限限制
		ProtocolType:     "POST",
		// 处理过程
		Processor: func(w http.ResponseWriter, r *http.Request, v map[string]interface{}) {
			// 创建一个认证
			info, uuid := H.ManagementKey.Add()
			info.Key, _ = v["Key"].(string)
			info.LifeCycle = 300
			// 创建终端
			// 根据平台创建命令行
			cmd := ""
			switch runtime.GOOS {
			case "darwin", "linux":
				cmd = "bash"
			case "windows":
				cmd = "cmd"
			}
			H.management[uuid], _ = NewCmd(cmd)
			// 返回
			w.Write([]byte(uuid))
		},
	}
	// 其他设置
	RunHandle := Run.Routing()
	// 跨域
	RunHandle.CrossDomain = H.CrossDomain
	// 认证
	RunHandle.VisitLimit = H.VisitLimit
	RunHandle.UsingVisitLimit = H.UsingVisitLimit
	H.Handle.Handle[RunHandle] = Run
	// ---------------------Exec 执行命令---------------------
	Exec := &protocol.Protocol{
		Path:   H.Path + `/Exec`,
		RegExp: false,
		// Key设置
		Key:              H.Key,
		UsingKey:         H.UsingKey,
		UsingToPrivilege: true, // 使用权限限制
		ProtocolType:     "GET",
		// 处理过程
		Processor: func(w http.ResponseWriter, r *http.Request, v map[string]interface{}) {
			//  判断用户 Key
			if _, ok := H.ManagementKey.IfKey(v, "CommandKey"); !ok {
				w.WriteHeader(http.StatusNotFound)
				return
			}
			// 得到终端
			key, ok := v["CommandKey"].([]string)
			if !ok {
				w.WriteHeader(http.StatusNotFound)
				return
			}
			command, ok := H.management[key[0]]
			if !ok {
				w.WriteHeader(http.StatusNotFound)
				return
			}
			if command == nil {
				w.WriteHeader(http.StatusNotFound)
				return
			}
			// 读取流
			Stdout := command.Stdout
			Stderr := command.Stderr
			// 注册到长链接
			websocket.Handler(func(ws *websocket.Conn) {
				go func() {
					for {
						line, err2 := Stdout.ReadString('\n')
						if err2 != nil || io.EOF == err2 {
							break
						}
						websocket.Message.Send(ws, line)
					}
				}()
				go func() {
					for {
						line, err2 := Stderr.ReadString('\n')
						if err2 != nil || io.EOF == err2 {
							break
						}
						websocket.Message.Send(ws, line)
					}
				}()
				// 主循环
				var cmd string
				for {
					// 接收消息
					if err := websocket.Message.Receive(ws, &cmd); err == nil {
						// 执行命令
						command.Exec(cmd)
					}
				}
			}).ServeHTTP(w, r)
		},
	}
	// 其他设置
	ExecHandle := Exec.Routing()
	// 跨域
	ExecHandle.CrossDomain = H.CrossDomain
	// 认证
	ExecHandle.VisitLimit = H.VisitLimit
	ExecHandle.UsingVisitLimit = H.UsingVisitLimit
	H.Handle.Handle[ExecHandle] = Exec
	// ---------------------Exit 退出终端---------------------
	Exit := &protocol.Protocol{
		Path:   H.Path + `/Exit`,
		RegExp: false,
		// Key设置
		Key:              H.Key,
		UsingKey:         H.UsingKey,
		UsingToPrivilege: true, // 使用权限限制
		ProtocolType:     "POST",
		// 处理过程
		Processor: func(w http.ResponseWriter, r *http.Request, v map[string]interface{}) {
			// 认证
			info, ok := H.ManagementKey.IfKey(v, "CommandKey")
			if !ok {
				w.WriteHeader(http.StatusNotFound)
				return
			}
			if info.Key != v["Key"].(string) {
				w.WriteHeader(http.StatusNotFound)
				return
			}
			// 得到终端 Key
			key, _ := v["CommandKey"].(string)
			// 销毁
			H.management[key].Exit()    // 退出终端
			delete(H.management, key)   // 删除终端
			H.ManagementKey.Delete(key) // 删除终端Key
		},
	}
	// 其他设置
	CloseHandle := Exit.Routing()
	// 跨域
	CloseHandle.CrossDomain = H.CrossDomain
	// 认证
	CloseHandle.VisitLimit = H.VisitLimit
	CloseHandle.UsingVisitLimit = H.UsingVisitLimit
	H.Handle.Handle[CloseHandle] = Exit
	// ---------------------HeartBeat 心跳包---------------------
	HeartBeat := &protocol.Protocol{
		Path:   H.Path + `/HeartBeat`,
		RegExp: false,
		// Key设置
		Key:              H.Key,
		UsingKey:         H.UsingKey,
		UsingToPrivilege: true, // 使用权限限制
		ProtocolType:     "POST",
		// 处理过程
		Processor: func(w http.ResponseWriter, r *http.Request, v map[string]interface{}) {
			if Info, ok := H.ManagementKey.IfKey(v, "CommandKey"); ok {
				(*Info).LifeCycle = 300
				w.Write([]byte("Ok"))
				return
			}
			w.Write([]byte("NO"))
		},
	}
	// 其他设置
	HeartBeatHandle := HeartBeat.Routing()
	// 跨域
	HeartBeatHandle.CrossDomain = H.CrossDomain
	// 认证
	HeartBeatHandle.VisitLimit = H.VisitLimit
	HeartBeatHandle.UsingVisitLimit = H.UsingVisitLimit
	H.Handle.Handle[HeartBeatHandle] = HeartBeat
}
